package com.chenl.provider.DEMOS.多线程相关;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.chenl.provider.DTO.entity.MyStudent;
import com.chenl.provider.mapper.StuMapper;
import lombok.extern.slf4j.Slf4j;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.sql.Connection;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;


/**
 * 多线程事务控制demo
 */
@Slf4j
@RestController
@RequestMapping("/async")
public class TransactionDemoController extends ServiceImpl<StuMapper, MyStudent> {
    /**
     * 分析： 分析打印3为什么是1，InheritableThreadLocal的继承性是在new Thread创建子线程时候
     * 在构造函数内把父线程内线程变量拷贝到子线程内部的。 为了不在创建新线程耗费资源，我们一般会用线程池,
     * 线程池的线程会复用，那么线程中的ThreadLocal便不对了，可能是旧的，因为线程是旧的。
     * @param args
     */
    public static void main(String[] args) {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(1,1,1, TimeUnit.MINUTES,new ArrayBlockingQueue<>(1));
        ThreadLocal local = new InheritableThreadLocal();
        local.set(1);

        executor.execute(()->{
            System.out.println("打印1:"+local.get()+" "+Thread.currentThread().getName());
            local.remove();
        });
        local.set(2);
        System.out.println("打印2:"+local.get()+" "+Thread.currentThread().getName());
        executor.execute(()->{
            System.out.println("打印3:"+local.get()+" "+Thread.currentThread().getName());
        });
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("打印4:"+local.get()+" "+Thread.currentThread().getName());
            }
        }).start();
        executor.shutdown();
    }

    @Autowired
    private DataSourceTransactionManager dataSourceTransactionManager;
    @Autowired
    private TransactionDefinition transactionDefinition;

    @Autowired
    ThreadPoolTaskExecutor threadPoolTaskExecutor;


    /**
     * 多线程事务控制,采用Spring提供的手动开启和手动提交的方式,利用await使得所有线程等待后,判断flag是否出异常标识,来决定每个线程是否提交
     * @return
     * @throws Exception
     */
    @PostMapping(value = "/test" )
    public String testt2() throws Exception{
        CyclicBarrier cyclicBarrier=new CyclicBarrier(3);
        MyStudent student=new MyStudent();
        student.setStuName("张三1");
        student.setStuAge("22");
        student.setPhone("17720885142");
        AtomicBoolean flag=new AtomicBoolean(true);
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        executorService.submit(()->{
            TransactionStatus transactionStatus = null;
            try {
                transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);//手动开启事务
                MyStudent student2=new MyStudent();
                student2.setStuName("李四2");
                student2.setStuAge("233");
                student2.setPhone("177208851423");
                this.save(student2);
//                System.out.println(1/0);//触发异常
            } catch (Exception e) {
                flag.set(false);
            }
            try {
                log.info("结束0");
                cyclicBarrier.await();
            } catch (Exception e){}
            if (flag.get()){
                log.info(Thread.currentThread().getName()+"提交了");
                dataSourceTransactionManager.commit(transactionStatus);//手动提交事务
            }else {
                log.info(Thread.currentThread().getName()+"回滚了");
                dataSourceTransactionManager.rollback(transactionStatus);//手动回滚事务
            }
        });
        executorService.submit(()->{
            TransactionStatus transactionStatus = null;
            try {
                transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
                MyStudent student2=new MyStudent();
                student2.setStuName("王五3");
                student2.setStuAge("444");
                student2.setPhone("177208851444");
                this.save(student2);
            } catch (Exception e) {
                flag.set(false);
            }
            try {
                log.info("结束1");
                cyclicBarrier.await();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            if (flag.get()){
                log.info(Thread.currentThread().getName()+"提交了");
                dataSourceTransactionManager.commit(transactionStatus);
            }else {
                log.info(Thread.currentThread().getName()+"回滚了");
                dataSourceTransactionManager.rollback(transactionStatus);
            }
        });
        executorService.shutdown();
        TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
        this.save(student);
        cyclicBarrier.await();
        log.info("结束2");
        if (flag.get()){
            log.info(Thread.currentThread().getName()+"提交了");
            dataSourceTransactionManager.commit(transactionStatus);
            return "提交了";
        }else {
            log.info(Thread.currentThread().getName()+"回滚了");
            dataSourceTransactionManager.rollback(transactionStatus);
            return "回滚了";
        }
    }
    @Autowired
    SqlSessionTemplate sqlSessionTemplate;
    @PostMapping(value = "/test2" )
    public String testt3() throws Exception{
        Connection connection = sqlSessionTemplate.getConnection();
        connection.setAutoCommit(false);
        connection.rollback();
        connection.commit();
        connection.close();
        return "ok";
    }
}
